from django.db import models
from django.contrib import auth
import datetime
import re
import search
from helper import new_rfc_serial
from helper import new_unix_serial
from django.contrib.auth.models import User
from django.db.models.fields.related import ManyToManyField
from django.contrib import admin
from reversion.admin import VersionAdmin
from django import forms
from django.forms import ModelForm

class Acl(models.Model):
	type = models.CharField(
		max_length=255,
		unique=True,
		)
	key = models.CharField(
		max_length=255,
		unique=True,
		)
	def __unicode__(self):
		return self.key
	def get_absolute_url(self):
		return "/dns/acl/%s/" % self.id
	class Meta:
		permissions = (
		)	
		get_latest_by = "id"
		ordering = ['key']
		verbose_name = "access control list"
		verbose_name_plural = "access control lists"	

class AclAdmin(VersionAdmin):
	list_display = ('type', 'key',)
	list_display_links = ('type',)
	list_filter = ()
	list_select_related = True
	ordering = ('-type',)
	save_as = True
	save_on_top = True
	search_fields = ('type', 'key',)

class Cryptokey(models.Model):
	domain = models.ForeignKey(
		'Domain',
		verbose_name="Domain",
		help_text="to which Domain/Zone do you want these records to be added to?",
		)
	flags = models.IntegerField(
		null=True,
		blank=True,
		help_text="",
		)
	active = models.BooleanField(
		blank=True,
		help_text="",
		)
	content = models.CharField(
		max_length=4096,
	)
	def __unicode__(self):
		return str(self.id)
	def get_absolute_url(self):
		return "/dns/cryptokey/%s/" % self.id
	class Meta:
		permissions = (
		)	
		get_latest_by = "id"
		ordering = ['id']
		verbose_name = "cryptokey"
		verbose_name_plural = "cryptokeys"	

class CryptokeyAdmin(VersionAdmin):
	list_display = ('flags', 'active', 'content')
	list_display_links = ('flags',)
	list_filter = ()
	list_select_related = True
	ordering = ('-active',)
	save_as = True
	save_on_top = True
	search_fields = ('flags', 'active', 'content')

class Domainmetadata(models.Model):
	domain = models.ForeignKey(
		'Domain',
		verbose_name="Domain",
		help_text="to which Domain/Zone do you want these records to be added to?",
		)
	kind = models.CharField(
		max_length=4096,
	)
	content = models.CharField(
		max_length=4096,
	)
	def __unicode__(self):
		return str(self.id)
	def get_absolute_url(self):
		return "/dns/domainmetadata/%s/" % self.id
	class Meta:
		permissions = (
		)	
		get_latest_by = "id"
		ordering = ['id']
		verbose_name = "domainmetadata"
		verbose_name_plural = "domainmetadata"	

class DomainmetadataAdmin(VersionAdmin):
	list_display = ('kind', 'content',)
	list_display_links = ('kind',)
	list_filter = ()
	list_select_related = True
	ordering = ('-kind',)
	save_as = True
	save_on_top = True
	search_fields = ('kind', 'content',)

class Nameserver(models.Model):
	name = models.CharField(
		max_length=255,
		unique=True,
		help_text="enter the Fully Qualified DomainName (FQDN) i.e. ns1.example.com of your nameserver here.",
		)
	ip = models.IPAddressField(
		help_text="What will the IPv4 Address of your nameserver be?",
		)
	ipv6 = models.CharField(
		max_length=255,
		blank=True,
		verbose_name="IPv6 Address",
		help_text="optionally enter the IPv6 Address of your nameserver here.",
		)
	def __unicode__(self):
		return self.name
	def get_absolute_url(self):
		return "/dns/nameserver/%s/" % self.id
	class Meta:
		permissions = (
		)
		get_latest_by = "id"
		ordering = ['name']
		verbose_name = "nameserver"
		verbose_name_plural = "nameservers"

class NameserverAdmin(VersionAdmin):
	list_display = ('name', 'ip',)
	list_display_links = ('name',)
	list_filter = ()
	list_select_related = True
	ordering = ('-name',)
	save_as = True
	save_on_top = True
	search_fields = ('name', 'ip',)
		
class Supermaster(models.Model):
	ip = models.IPAddressField(
		unique=True,
		help_text="IPv4 Address of the Supermaster",
		)
	nameserver = models.CharField(
		max_length=255,
		unique=True,
		help_text="DNS Name of the Supermaster",
		)
	account = models.CharField(
		max_length=40,
		blank=True,
		editable=False,
		help_text="",
		)
	def __unicode__(self):
		return self.nameserver
	def get_absolute_url(self):
		return "/dns/supermaster/%s/" % self.id
	class Meta:
		permissions = (
		)	
		get_latest_by = "id"
		ordering = ['nameserver']
		verbose_name = "supermaster"
		verbose_name_plural = "supermasters"	
		
class SupermasterAdmin(VersionAdmin):
	list_display = ('nameserver', 'ip',)
	list_display_links = ('nameserver', 'ip')
	list_filter = ()
	list_select_related = True
	ordering = ('-nameserver',)
	save_as = True
	save_on_top = True
	search_fields = ('ip', 'nameserver',)
		
	
class Domain(models.Model):
	DOMAIN_TYPES = (
		('NATIVE', 'Native'),
		('MASTER', 'Master'),
		('SLAVE', 'Slave'),
	)
	name = models.CharField(
		max_length=255,
		unique=True,
		help_text="What is your Domainname? you can call it a Zone if you like too.",
		)
	master = models.CharField(
		max_length=128,
		null=True,
		blank=True,
		help_text="",
		)
	last_check = models.IntegerField(
		null=True,
		blank=True,
		help_text="",
		)
	type = models.CharField(
		max_length=6,
		choices=DOMAIN_TYPES,
		default='Native',
		help_text="Native SQL Replication or master/slave Zonetransfer Setup?",
		)
	notified_serial = models.IntegerField(
		null=True,
		blank=True,
		help_text="",
		)
	account = models.CharField(
		null=True,
		max_length=40,
		blank=True,
		help_text="",
		)
	serial = models.IntegerField(
		verbose_name="serial number",
		default=new_rfc_serial,
		help_text="The Serial Number for your Domains SOA record.",
		)
	default_ttl = models.IntegerField(
		verbose_name="default TTL",
		default=86400,
		help_text="Which default TimeToLive should records in your Zone have?",
		)
	refresh_ttl = models.IntegerField(
		verbose_name="refresh TTL",
		default=28800,
		help_text="Interval in seconds the Zone is checked for changes at the master. Can be ignored for Type Native.",
		)
	retry_ttl = models.IntegerField(
		verbose_name="retry TTL",
		default=14400,
		help_text="Interval when to retry the check of the Zone on the master if it didn't succeed the first time for a refresh. Can be ignored for Type Native.",
		)
	expire_ttl = models.IntegerField(
		verbose_name="expire TTL",
		default=3600000,
		help_text="Time in seconds after which the Zone will expire from our Nameservers if no contact can be made with the master. Can be ignored for Type Native.",
		)
	minimum_ttl = models.IntegerField(
		verbose_name="minimum TTL",
		default=86400,
		help_text="Can be ignored for Type Native.",
		)
	soa_nameserver = models.CharField(
		verbose_name="nameserver for SOA",
		max_length=255,
		help_text="this part of your Zone's SOA record states which nameserver is responsible for maintaining the data.",
		)
	nameservers = models.ManyToManyField(
		'Nameserver',
		verbose_name="the delegated Nameservers",
		help_text="make sure the Nameservers delegated for your Zone match those listed here.",
		)
	admin_mailbox = models.EmailField(
		verbose_name="admin mailbox for SOA",
		help_text="this should list the email address of the person responsible for changes to the Zone. Cannot have a dot before the @-sign.",
		)
	allow_users = models.BooleanField(
		verbose_name="allow users",
		default=True,
		help_text="should other users be allowed to add or modify records in this Zone or should it be yours only to edit?",
		)
	description = models.CharField(
		verbose_name="describe item",
		max_length=4096,
		null=True,
		blank=True,
		help_text="describe your Zone here, for example what is it used for?",
		)
	def __unicode__(self):
		return self.name
	def get_absolute_url(self):
		return "/dns/domain/%s/" % self.id
	def show(self):
		opts=self._meta
		data={}
		for f in opts.fields + opts.many_to_many:
			if isinstance(f, ManyToManyField):
				data[f.name] = [obj for obj in f.value_from_object(self)]
			else:
				data[f.name]=f.value_from_object(self)
		return data
	class Meta:
		permissions = (
		)
		get_latest_by = "id"
		ordering = ['id']
		verbose_name = "domain"
		verbose_name_plural = "domains"

class DomainAdmin(VersionAdmin):
	list_display = ('name', 'allow_users', 'default_ttl', 'serial', 'type')
	list_display_links = ('name',)
	list_filter = ('allow_users', 'type', 'soa_nameserver',)
	list_select_related = True
	ordering = ('-name',)
	save_as = True
	save_on_top = True
	search_fields = ('name', 'description', 'soa_nameserver', 'admin_mailbox')

class Record(models.Model):
	RECORD_TYPES = (
	    ('A', 'A'),
	    ('PTR', 'PTR'),
	    ('AAAA', 'AAAA'),
		('MX', 'MX'),
		('NS', 'NS'),
		('SRV', 'SRV'),
		('TXT', 'TXT'),
		('SOA', 'SOA'),
	    ('AFSDB', 'AFSDB'),
	    ('CERT', 'CERT'),
		('CNAME', 'CNAME'),
		('DNSKEY', 'DNSKEY'),
		('DS', 'DS'),
		('HINFO', 'HINFO'),
		('KEY', 'KEY'),
		('LOC', 'LOC'),
		('NAPTR', 'NAPTR'),
		('NSEC', 'NSEC'),
		('RP', 'RP'),
		('RRSIG', 'RRSIG'),
		('SPF', 'SPF'),
		('SSHFP', 'SSHFP'),
	)
	domain = models.ForeignKey(
		'Domain',
		verbose_name="Domain",
		help_text="to which Domain/Zone do you want these records to be added to?",
		)
	name = models.CharField(
		max_length=255,
		help_text="can be either a hostname (without dots) or a FQDN String repeating the Domainname but without the ending dot.",
		)
	type = models.CharField(
		max_length=6,
		choices=RECORD_TYPES,
		default='A',
		help_text="choose the DNS INternet protocol record type here.",
		)
	content = models.CharField(
		max_length=255,
		help_text="here goes what you want your name to result in, i.e. either an IP-Address or other record text.",
		)
	ttl = models.IntegerField(
		null=False,
		blank=True,
		default=3600,
		help_text="the TimeToLive for this record. It determines how long in seconds it is cached/held on recursive Nameservers.",
		)
	prio = models.IntegerField(
		null=False,
		blank=True,
		default=0,
		help_text="enter the Priority of your record here but only if the chosen record type supports it, most type do not - just leave it at 0 then.",
		)
	description = models.CharField(
		max_length=4096,
		null=True,
		blank=True,
		help_text="_please_ describe what this record is for, me want more metadata!11!! ;-)",
		)
	dynamic = models.BooleanField(
		default=False,
		help_text="only set this to true _if_ the record is dynamically generated by dhcp, it _will_ get overwritten!"
		)
	auth = models.BooleanField(
		default=True,
		help_text="for DNSSEC: set to False if this is glue or NS records that point to another zone"
		)
	ordername = models.CharField(
		max_length=255,
		db_index=True,
		blank=True,
		help_text="for DNSSEC: The ordername should contain the *relative* part of the record name in reverse canonical order. yay"
		)
	def __unicode__(self):
		return self.type + ' ' + self.name
	def get_absolute_url(self):
		return "/dns/record/%s/" % self.id
	class Meta:
		permissions = (
		)
		get_latest_by = "id"
		ordering = ['-id', 'name', 'type']
		verbose_name = "record"
		verbose_name_plural = "records"

class RecordAdmin(VersionAdmin):
	list_display = ('name', 'domain', 'type', 'content',)
	list_display_links = ('name', 'domain', 'type',)
	list_filter = ('type', 'domain', 'ttl', 'prio',)
	list_select_related = True
	ordering = ('-id',)
	save_as = True
	save_on_top = True
	search_fields = ('name', 'type', 'content', 'description')

search.register(Domain, fields=["name", "description"])
search.register(Record, fields=["domain", "name", "type", "content", "ttl", "prio", "description"])
search.register(Nameserver, fields=["name", "ip", "ipv6"])
search.register(Supermaster, fields=["ip", "nameserver"])
search.register(Acl, fields=["type", "key"])
search.register(Cryptokey, fields=["flags", "active", "content"])
search.register(Domainmetadata, fields=["kind", "content"])
